

#import "hyperlink_text_view.h"

// The baseline shift for text in the NSTextView.
const float kTextBaselineShift = -1.0;

@interface HyperlinkTextView(Private)
// Initialize the NSTextView properties for this subclass.
- (void)configureTextView;

// Change the current IBeamCursor to an arrowCursor.
- (void)fixupCursor;
@end

@implementation HyperlinkTextView

- (id)initWithCoder:(NSCoder*)decoder {
    if ((self = [super initWithCoder:decoder]))
        [self configureTextView];
    return self;
}

- (id)initWithFrame:(NSRect)frameRect {
    if ((self = [super initWithFrame:frameRect]))
        [self configureTextView];
    
    return self;
}

// Never draw the insertion point (otherwise, it shows up without any user
// action if full keyboard accessibility is enabled).
- (BOOL)shouldDrawInsertionPoint {
    return NO;
}

- (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange
                              granularity:(NSSelectionGranularity)granularity {
  // Do not allow selections.
    return NSMakeRange(0, 0);
}

// Convince NSTextView to not show an I-Beam cursor when the cursor is over the
// text view but not over actual text.
//
// http://www.mail-archive.com/cocoa-dev@lists.apple.com/msg10791.html
// "NSTextView sets the cursor over itself dynamically, based on considerations
// including the text under the cursor. It does so in -mouseEntered:,
// -mouseMoved:, and -cursorUpdate:, so those would be points to consider
// overriding."
- (void)mouseMoved:(NSEvent*)e {
    [super mouseMoved:e];
    [self fixupCursor];
}

- (void)mouseEntered:(NSEvent*)e {
    [super mouseEntered:e];
    [self fixupCursor];
}

- (void)cursorUpdate:(NSEvent*)e {
    [super cursorUpdate:e];
    [self fixupCursor];
}

- (void)configureTextView {
    [self setEditable:NO];
    [self setDrawsBackground:NO];
    [self setHorizontallyResizable:NO];
    [self setVerticallyResizable:NO];
}

- (void)fixupCursor {
    if ([[NSCursor currentCursor] isEqual:[NSCursor IBeamCursor]])
        [[NSCursor arrowCursor] set];
}

- (void)setMessageAtStart:(NSString*)startMsg
                 withLink:(NSString*)link
                      end:(NSString *)endMsg
                     font:(NSFont*)font
             messageColor:(NSColor*)messageColor
                linkColor:(NSColor*)linkColor{
    
    // start message
    NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
    [attributes setObject:messageColor
                   forKey:NSForegroundColorAttributeName];
    [attributes setObject:[NSCursor arrowCursor]
                   forKey:NSCursorAttributeName];
    [attributes setObject:font
                   forKey:NSFontAttributeName];
    [attributes setObject:[NSNumber numberWithFloat:kTextBaselineShift]
                   forKey:NSBaselineOffsetAttributeName];
    
    // Create the attributed string for the message.
    NSMutableAttributedString *attributedMessage = [[NSMutableAttributedString alloc] initWithString:startMsg                                        
                                                                                          attributes:attributes];
    if ([link length] != 0) {
        // Add additional attributes to style the link text appropriately as
        // well as linkify it.
        [attributes setObject:linkColor
                       forKey:NSForegroundColorAttributeName];
        [attributes setObject:[NSNumber numberWithBool:YES]
                       forKey:NSUnderlineStyleAttributeName];
        [attributes setObject:[NSCursor pointingHandCursor]
                       forKey:NSCursorAttributeName];
        [attributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle]
                       forKey:NSUnderlineStyleAttributeName];
        [attributes setObject:[NSString string]  // dummy value
                       forKey:NSLinkAttributeName];
        
        // Insert the link into the message at the appropriate offset.
        NSAttributedString *attributedLink = [[NSAttributedString alloc] initWithString:link
                                                                             attributes:attributes];
        [attributedMessage insertAttributedString:attributedLink
                                                atIndex:[startMsg length]];
        // Ensure the TextView doesn't override the link style.
        [self setLinkTextAttributes:attributes];
        [attributedLink release];
    }
    
    {
    NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
    [attributes setObject:messageColor
                   forKey:NSForegroundColorAttributeName];
    [attributes setObject:[NSCursor arrowCursor]
                   forKey:NSCursorAttributeName];
    [attributes setObject:font
                   forKey:NSFontAttributeName];
    [attributes setObject:[NSNumber numberWithFloat:kTextBaselineShift]
                   forKey:NSBaselineOffsetAttributeName];
    
    // Create the attributed string for the message.
    NSMutableAttributedString *endMessage = [[NSMutableAttributedString alloc] initWithString:endMsg
                                                                                       attributes:attributes];
    [attributedMessage insertAttributedString:endMessage
                                      atIndex:[startMsg length]+[link length]];
    [endMessage release];
    }
    
    // Update the text view with the new text.
    [[self textStorage] setAttributedString:attributedMessage];
    [attributedMessage release];
}

- (void)setMessageAndLink:(NSString*)message
                 withLink:(NSString*)link
                 atOffset:(NSUInteger)linkOffset
                     font:(NSFont*)font
             messageColor:(NSColor*)messageColor
                linkColor:(NSColor*)linkColor {
    // Create an attributes dictionary for the message and link.
    NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
    [attributes setObject:messageColor
                 forKey:NSForegroundColorAttributeName];
    [attributes setObject:[NSCursor arrowCursor]
                 forKey:NSCursorAttributeName];
    [attributes setObject:font
                 forKey:NSFontAttributeName];
    [attributes setObject:[NSNumber numberWithFloat:kTextBaselineShift]
                 forKey:NSBaselineOffsetAttributeName];

    // Create the attributed string for the message.
    NSMutableAttributedString *attributedMessage = [[NSMutableAttributedString alloc] initWithString:message
                                                                                          attributes:attributes];
    if ([link length] != 0) {
    // Add additional attributes to style the link text appropriately as
    // well as linkify it.
    [attributes setObject:linkColor
                   forKey:NSForegroundColorAttributeName];
    [attributes setObject:[NSNumber numberWithBool:YES]
                   forKey:NSUnderlineStyleAttributeName];
    [attributes setObject:[NSCursor pointingHandCursor]
                   forKey:NSCursorAttributeName];
    [attributes setObject:[NSNumber numberWithInt:NSSingleUnderlineStyle]
                   forKey:NSUnderlineStyleAttributeName];
    [attributes setObject:[NSString string]  // dummy value
                   forKey:NSLinkAttributeName];

    // Insert the link into the message at the appropriate offset.
      NSAttributedString *attributedLink = [[NSAttributedString alloc] initWithString:link
                                                                           attributes:attributes];
    [attributedMessage insertAttributedString:attributedLink
                                            atIndex:linkOffset];
    // Ensure the TextView doesn't override the link style.
    [self setLinkTextAttributes:attributes];
    }

    // Update the text view with the new text.
    [[self textStorage] setAttributedString:attributedMessage];
    [attributedMessage release];
}

@end
